﻿using IcIntegration.Job;
using IcIntegration.Job.Options;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Quartz;
using System;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;

namespace IcIntegration.Job
{
    public class RegisterJobService : IHostedService
    {
        private readonly ILogger _logger;
        private readonly ISchedulerFactory _schedulerFactory;
        private readonly IConfiguration _configuration;
        private readonly IServiceProvider _serviceProvider;
        private readonly IScheduler _scheduler;

        public RegisterJobService(ILogger<RegisterJobService> logger,
            ISchedulerFactory schedulerFactory,
            IConfiguration configuration,
            IServiceProvider serviceProvider)
        {
            this._logger = logger;
            this._schedulerFactory = schedulerFactory;
            this._configuration = configuration;
            this._serviceProvider = serviceProvider;
            this._scheduler = _schedulerFactory.GetScheduler().Result;
            _scheduler.JobFactory = new JobFactory(_serviceProvider);
        }

        public async Task StartAsync(CancellationToken cancellationToken = default)
        {
            await Task.Factory.StartNew(async () =>
            {
                _logger.LogDebug("任务开始");
                var assembly = Assembly.GetExecutingAssembly();
                var jobTypes = assembly.GetTypes().Where(c => typeof(IJob).IsAssignableFrom(c) && !c.IsAbstract).ToList();

                foreach (var jobType in jobTypes)
                {
                    var jobName = jobType.Name;
                    var jobAttribute = GetJobConfig(jobName);
                    if (!jobAttribute.IsEnabled)
                        continue;
                    await AddJob(jobType, jobAttribute.Crontab, jobAttribute.JobName, jobAttribute.Description);
                }
                await _scheduler.Start();
                _logger.LogDebug($"服务启动成功!");
            }, cancellationToken);
        }

        public async Task StopAsync(CancellationToken cancellationToken = default)
        {
            await _scheduler.Shutdown();
        }

        private async Task AddJob(Type jobType, string cron, string jobName, string description)
        {
            var groupName = jobName + "_group";
            var triggerName = jobName + "_trigger";
            var triggerGroupName = groupName;

            var job = JobBuilder.Create(jobType)
                            .WithIdentity(jobName, groupName)
                            .WithDescription(description)
                            .Build();

            var trigger = TriggerBuilder.Create()
                                .WithIdentity(triggerName, triggerGroupName)
                                .WithSchedule(CronScheduleBuilder.CronSchedule(new CronExpression(cron)))
                                .StartNow()
                                .Build();

            await _scheduler.ScheduleJob(job, trigger);
            _logger.LogDebug($"注册服务{jobName}成功");
        }

        private JobOptions GetJobConfig(string jobName)
        {
            var option = new JobOptions();
            _configuration.GetSection($"JobConfig:{jobName}").Bind(option);
            option.JobName = jobName;
            return option;
        }
    }
}
